import { nextTick } from 'vue'
import axios from 'axios'
// import { ElLoading, ElMessage } from 'element-plus'
// import { ElNotification as Notify } from 'element-plus'
import type { AxiosError, AxiosResponse } from 'axios'

// 拓展 axios, 判断是否加载 加载条
declare module 'axios' {
  export interface AxiosRequestConfig {
    showLoading?: boolean
  }
}

/**
 * 响应类型
 */
export interface ResponseType<T = object> {
  errorCode: number
  topMessage?: string
  data?: T
}

export interface ResponseTypePage<T = object> {
  errorCode: number
  topMessage?: string
  data?: T
  pageIndex: number
  pageSize: number
  total?: number
}

// 请求配置
const service = axios.create({
  timeout: 1000 * 15, // 超时时间
})

let loadingInstance: {
  close: () => void
}

const startLoding = () => {
  // // 加载 element ui的进度条, 避免重复加载, 也可以使用 axios 原生的取消重复请求
  // loadingInstance = ElLoading.service({
  //   lock: true,
  //   fullscreen: true,
  //   body: true,
  //   text: '加载中...',
  //   background: 'rgba(0, 0, 0, 0.7)',
  // })

  console.log(`output-> 加载进度条`)
  loadingInstance = {
    close: () => {
      console.log(`output-> 关闭进度条`)
    },
  }
}

const endLoading = async () => {
  // 取消进度条
  if (loadingInstance) await nextTick(() => setTimeout(() => loadingInstance.close(), 200))
}

// 请求拦截
service.interceptors.request.use(async (config) => {
  const { VITE_BASE_API_URL } = window.__env__

  config.baseURL = VITE_BASE_API_URL

  const { showLoading } = config
  if (showLoading) startLoding()

  config.headers['Content-Type'] = 'application/x-www-form-urlencoded'

  // 如果token 存在,则携带token 做请求
  // config.headers['authorization'] = `Bearer ${session.getToken()}`
  // interceptorConfig.headerTokenConfig(config)
  return config
})

// 响应拦截
// 通过拦截非200~300 之间的状态码,减少直接请求的逻辑判断
service.interceptors.response.use(
  async (res: AxiosResponse) => {
    await endLoading()

    // 处理的自定义错误
    // 大于 1000 的为自定义异常
    if (res.data.errorCode >= 200 && res.data.errorCode < 300) {
      return Promise.resolve(res)
    } else if (res.data.errorCode >= 1000) {
      return Promise.resolve(res)
    } else {
      console.error(res.data.topMessage)
      // Notify({
      //   title: '错误',
      //   message: res.data.topMessage,
      //   type: 'error',
      // })
      return Promise.reject(res)
    }
  },
  async (err: AxiosError) => {
    // 取消进度条
    await endLoading()

    // 判断非 定义的状态码,如网络异常
    if (err.response) stateCode(err.response.status)
    else {
      if (err.code == 'ERR_NETWORK') stateCode(506)
      else stateCode(500)
    }

    // 将函数进行回调
    return Promise.reject(err.message)
  },
)

// 如果 捕获到错误,在这里处理,让单个组件请求时,都是200的状态码
// get 请求

export const request = {
  /**
   * get请求
   * @param url 请求地址
   * @param params 参数
   * @param showLoading 是否 显示加载动画
   * @returns
   */
  getAsync: <T = object>(
    url: string,
    params?: object | null,
    showLoading: boolean = true,
  ): Promise<ResponseType<T>> =>
    new Promise((resolve, reject) =>
      service
        .get(url, {
          params,
          showLoading,
        })
        .then((res) => resolve(res.data as ResponseType<T>))
        .catch((err: object) => reject(err)),
    ),

  /**
   * 分页请求
   * @param url 请求地址
   * @param params 参数
   * @param showLoading 是否 显示加载动画
   * @returns
   */
  getPageAsync: <T = object>(
    url: string,
    params?: object,
    showLoading: boolean = true,
  ): Promise<ResponseTypePage<T>> =>
    new Promise((resolve, reject) =>
      service
        .get(url, {
          params,
          showLoading,
        })
        .then((res) => resolve(res.data as ResponseTypePage<T>))
        .catch((err: object) => reject(err)),
    ),

  /**
   * post请求
   * @param url 请求地址
   * @param data 参数
   * @param showLoading 是否 显示加载动画
   * @returns
   */
  postAsync: <T = object>(
    url: string,
    data?: object,
    showLoading: boolean = true,
  ): Promise<ResponseType<T>> =>
    new Promise((resolve, reject) =>
      service
        .post(url, data, { showLoading })
        .then((res) => resolve(res.data as ResponseType<T>))
        .catch((err: object) => reject(err)),
    ),

  /**
   * put请求
   * @param url 请求地址
   * @param data 参数
   * @param showLoading 是否 显示加载动画
   * @returns
   */
  putAsync: <T = object>(
    url: string,
    data?: object,
    showLoading: boolean = true,
  ): Promise<ResponseType<T>> =>
    new Promise((resolve, reject) => {
      service
        .put(url, data, { showLoading })
        .then((res) => resolve(res.data as ResponseType<T>))
        .catch((err) => reject(err))
    }),

  /**
   * patch请求
   * @param url 请求地址
   * @param showLoading 是否 显示加载动画
   * @returns
   */
  patchAsync: <T = object>(url: string, showLoading: boolean = true): Promise<ResponseType<T>> =>
    new Promise((resolve, reject) => {
      service
        .patch(url, { showLoading })
        .then((res) => resolve(res.data as ResponseType<T>))
        .catch((err) => reject(err))
    }),

  /**
   * delete请求
   * @param url 请求地址
   * @param showLoading 是否 显示加载动画
   * @returns
   */
  deleteAsync: <T = object>(url: string, showLoading: boolean = true): Promise<ResponseType<T>> =>
    new Promise((resolve, reject) => {
      service
        .delete(url, { showLoading })
        .then((res) => resolve(res.data as ResponseType<T>))
        .catch((err) => reject(err))
    }),
}

/**
 * 针对不同的状态码进行显示
 * 拦截错误的响应
 * 处理的系统的错误
 * @param code
 */
const stateCode = (code: number) => {
  let msg
  switch (code) {
    case 400:
      msg = '请求错误(400)'
      break
    case 401:
      msg = '未授权，请重新登录(401)'
      break
    case 403:
      msg = '拒绝访问(403)'
      break
    case 404:
      msg = '请求出错(404)'
      break
    case 408:
      msg = '请求超时(408)'
      break
    case 500:
      msg = '服务器错误(500)'
      break
    case 501:
      msg = '服务未实现(501)'
      break
    case 502:
      msg = '网络错误(502)'
      break
    case 503:
      msg = '服务不可用(503)'
      break
    case 504:
      msg = '网络超时(504)'
      break
    case 505:
      msg = 'HTTP版本不受支持(505)'
      break
    case 506:
      msg = '网络请求失败, 请检查服务器是否正常'
      break
    default:
      msg = '未知错误联系管理员'
      break
  }
  // ElMessage({
  //   message: msg,
  //   type: 'error',
  // })
  console.error(msg)
}
